package youtube.tv.authentication

import grails.converters.JSON
import org.springframework.web.context.request.RequestContextHolder
import org.codehaus.groovy.grails.web.json.JSONElement
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

/**
 * @author Sergey Istomin
 */
class SocialAuthenticationService {

    def grailsApplication
    
    Boolean isLoggedIn() {
        return getUser() != null
    }
    
    AppUser getUser() {
        def request = RequestContextHolder.currentRequestAttributes()
        String signedRequest = request.parameterMap['signed_request']?.toString()
        if (signedRequest) {
            JSONElement decodedUser = parseSignedRequest(signedRequest)
            if (decodedUser['user_id']) {
                return new AppUser(userId: decodedUser['user_id'])
            }
        }
        return null
    }

    /**
     * It parses the signed request and it returns a json object with the signed params if the
     * sign is verify, and null otherwise.
     *
     * @see http://developers.facebook.com/docs/authentication/signed_request
     */
    private JSONElement parseSignedRequest(String signedRequest) {
        def result
        byte[] payloadSig
        String sig, payload
        String[] pair = signedRequest.split('\\.')

        if (pair.size() != 2) {
            log.warn "Signed request bad format: $signedRequest"
        } else {
            sig = unUrl(pair[0])
            payload = unUrl(pair[1])
            payloadSig = computePayloadSignature(payload)

            if (sig.decodeBase64() == payloadSig) {
                result = JSON.parse(new String(payload.decodeBase64()))
            }
        }
        return result
    }

    /**
     * It makes these replaces:
     * + by -
     * / by _
     */
    private String unUrl(String input) {
        return input.replace('_', '/').replace('-', '+')
    }

    /**
   	 * This method generates the signature of the payload passed as parameter,
   	 * using the Facebook application secret as secret for the HmacSHA256 algorithm.
   	 */
   	private byte[] computePayloadSignature(String payload) {
   		String applicationSecret = grailsApplication.config.facebook.applicationSecret
   		Mac mac = Mac.getInstance('HmacSHA256')
   		mac.init(new SecretKeySpec(applicationSecret.bytes, 'HmacSHA256'))
   		return mac.doFinal(payload.bytes)
   	}

}
